package storage

import (
	"encoding/json"
	"fmt"
	"github.com/duke-git/lancet/v2/strutil"
	"go-iot-gateway/internal/apk/files"
	storage_define "go-iot-gateway/internal/storage/define"
	memory_storage "go-iot-gateway/internal/storage/impl/memory"
	sqlite_storage "go-iot-gateway/internal/storage/impl/sqlite"
	storage_processor "go-iot-gateway/internal/storage/processor"
	sys_config "go-iot-gateway/internal/sys/config"
	"os"
	"strings"
)

const (
	STORAGE_TYPE_SQL = "sql"
)

type mixtureStorage struct {
	storage_define.LatestStorage
	storage_define.HistoryStorage
}

func (receiver *mixtureStorage) CloseStorage() {
	receiver.LatestStorage.CloseStorage()
	receiver.HistoryStorage.CloseStorage()
}

var storage_instance storage_define.Storage

// 初始化数据库
func InitStorage(env sys_config.StorageEnv) error {
	fmt.Printf("\n ===== 初始化STORAGE ===== \n")
	jsonData, _ := json.Marshal(env)
	fmt.Printf("%s \n", string(jsonData))

	//目录创建
	dataPath := env.Path
	if strutil.IsBlank(dataPath) {
		dataPath = sys_config.HomeDir() + string(os.PathSeparator) + "data" // 默认路径
	}
	realDataPath, err := files.Mkdir(dataPath)
	if err != nil {
		panic(err)
	}
	fmt.Println("数据存储路径 :" + realDataPath)

	//创建实时库
	var latestStorage storage_define.LatestStorage

	if env.LatestStorage.Type == STORAGE_TYPE_SQL {

		if strings.Contains(env.LatestStorage.Datasource.DriverClassName, "sqlite") ||
			strings.TrimSpace(env.LatestStorage.Datasource.DriverClassName) == "" {
			latestStorage, err = newSqliteLatestStorage(env.LatestStorage, realDataPath)
			if err != nil {
				return err
			}
		}

	}

	//创建历史库
	var historyStorage storage_define.HistoryStorage
	if env.HistoryStorage.Enable {
		if env.HistoryStorage.Type == STORAGE_TYPE_SQL {

			if strings.Contains(env.LatestStorage.Datasource.DriverClassName, "sqlite") ||
				strings.TrimSpace(env.LatestStorage.Datasource.DriverClassName) == "" {
				historyStorage, err = sqlite_storage.NewLHistoryStorage(env.HistoryStorage, realDataPath)
				if err != nil {
					panic(err)
				}
			}

		}
	}

	if historyStorage == nil {
		historyStorage = &memory_storage.MemoryHistoryStorage{}
	}

	storage_instance = &mixtureStorage{
		latestStorage,
		historyStorage,
	}

	return nil
}

func newSqliteLatestStorage(env sys_config.LatestStorageEnv, dataPath string) (storage_define.LatestStorage, error) {
	datasourceUrl := env.Datasource.Url
	if strutil.IsBlank(datasourceUrl) {
		dataPath = dataPath + string(os.PathSeparator)
		datasourceUrl = "jdbc:sqlite:" + dataPath + "latest-sqlite.db"
	}

	latestStorage, err := sqlite_storage.NewLatestStorage(datasourceUrl, sqlite_storage.FlushConfig{
		FlushCacheSize:  env.FlushCacheSize,
		FlushSize:       env.FlushSize,
		FlushIntervalMs: env.FlushIntervalMs,
	})
	return latestStorage, err
}

// 保存值，不通知变动
func SaveVal(val storage_define.ValObject) {
	val = storage_processor.DirectProcessorByTag(val)
	storage_instance.SaveVal(val)
}

// 通知值变动
func NotifyVal(tagName string) {
	storage_instance.NotifyVal(tagName)
}

// 保存并通知值变动
func SaveAndNotify(val storage_define.ValObject) {
	val = storage_processor.DirectProcessorByTag(val)
	storage_instance.SaveAndNotify(val)
}

// 固定值
func FixedVal(tagName string, val interface{}) {
	storage_instance.FixedVal(tagName, val)
}

// 取消固化
func UnFixedVal(tagName string) {
	storage_instance.UnFixedVal(tagName)
}

// 数据变化订阅
func SubscribeNotify(subNo string) {
	storage_instance.SubscribeNotify(subNo)
}

// 取消订阅
func UnSubscribeNotify(subNo string) {
	storage_instance.UnSubscribeNotify(subNo)
}

// // 查询值
func FindLatestVal(tagName string) (storage_define.ValObject, error) {
	return storage_instance.FindLatestVal(tagName)
}

// //条件查询 todo 不使用sql ， 对其他不友好
func FindLatestBySQL(query interface{}, args ...interface{}) []storage_define.ValObject {
	return storage_instance.FindLatestBySQL(query, args...)
}

// 是否存在
func ExistsLatestVal(tagName string) bool {
	return storage_instance.ExistsLatestVal(tagName)
}

// 关闭存储
func CloseStorage() {
	if storage_instance != nil {
		storage_instance.CloseStorage()
	}
}

//
////查看指定时间之前的记录
//FindBefore(time time.Time) []storage_define.ValObject
////条件查询
//FindByCriteria() []storage_define.ValObject
////分页查询
//Paging()
////关闭存储
//CloseStorage()
